package com.letu.elasticsearch.dao.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.letu.elasticsearch.dao.EsBaseDao;
import com.letu.elasticsearch.model.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.AnalyzeRequest;
import org.elasticsearch.client.indices.AnalyzeResponse;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.*;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.suggest.SortBy;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
public class EsBaseDaoImpl<T> implements EsBaseDao<T> {
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public <T> Iterable<T> save(Iterable<T> entities) {
        return elasticsearchRestTemplate.save(entities);
    }

    @Override
    public <T> T save(T t) {
        return elasticsearchRestTemplate.save(t);
    }

    @Override
    public Boolean delete(String id, Class<?> entityType) {
        String delete = elasticsearchRestTemplate.delete(id, entityType);
        return true;
    }

    @Override
    public Boolean delete(Object entity) {
        String delete = elasticsearchRestTemplate.delete(entity);
        return true;
    }

    @Override
    public Boolean delete(Query query, Class<?> entity) {
        elasticsearchRestTemplate.delete(query, entity, elasticsearchRestTemplate.getIndexCoordinatesFor(entity));
        return true;
    }

    @Override
    public Boolean update(String id, Object object, Class<?> classType) {
        UpdateQuery.Builder builder = UpdateQuery.builder(id)
                .withDocument(org.springframework.data.elasticsearch.core.document.Document.from(BeanUtil.beanToMap(object)));
        IndexCoordinates of = IndexCoordinates.of(classType.getAnnotation(Document.class).indexName());
        UpdateResponse update = elasticsearchRestTemplate.update(builder.build(), of);
        return true;
    }

    @Override
    public <T> T get(String id, Class<T> classType) {
        T t = elasticsearchRestTemplate.get(id, classType);
        return t;
    }

    @Override
    public Boolean exists(String id, Class<?> classType) {
        return elasticsearchRestTemplate.exists(id, classType);
    }

    @Override
    public <T> PageResult<T> selectFindPage(Integer pageNum, Integer pageSize, String key, String value, Class<T> classType) {
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(key, value).analyzer("ik_smart");//分词查询(这里指定分词只是分传过来的参数)[它是要和es索引里的分词后数据一一对应才能返回]
                                                                    /*例子：前台传了 (山东省:粗粒度分为山东省 细粒度分为：山东省,山东,省)
                                                                        es索引库里(山东省济南市 粗粒度分为 山东省,济南市  细粒度分为:山东省,山东,省,济南市,济南,市)
                                                                        只有当前台分的词和后台分的词能有一个匹配上就可以*/
        nativeSearchQueryBuilder.withQuery(matchQueryBuilder);
        nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNum == null || pageNum == 0 ? 0 : pageNum - 1, pageSize));
        //4.构建查询对象
        NativeSearchQuery query = nativeSearchQueryBuilder.build();

        IndexCoordinates of = IndexCoordinates.of(classType.getAnnotation(Document.class).indexName());

        //查询
        SearchHits<T> searchHits = elasticsearchRestTemplate.search(query, classType);
        //查询总数
        long count = elasticsearchRestTemplate.count(query, classType);

//最终结果集
        List<T> tList = new ArrayList<>();
        //添加高亮查询
        for (SearchHit<T> searchHit : searchHits) {
            //获取普通结果
            tList.add(searchHit.getContent());
        }

//        AggregatedPage<T> page = elasticsearchRestTemplate.queryForPage(query, classType, of);
//        long totalElements = page.getTotalElements(); // 总记录数
//        int totalPages = page.getTotalPages();  // 总页数
//        int pageNumber = page.getPageable().getPageNumber(); // 当前页号
//        List<T> beanList = page.toList();  // 当前页数据集
//        Set<T> beanSet = page.toSet();  // 当前页数据集
        //返回结果列表和查询总数
        return new PageResult<T>(count, tList);
    }

    @Override
    public List<AnalyzeResponse.AnalyzeToken> selectBreakUpText(String tokenizer, String text) throws NoSuchFieldException, IllegalAccessException, IOException {
        RestHighLevelClient restHighLevelClient = elasticsearchRestTemplate.execute((client) -> client);
        AnalyzeRequest request = AnalyzeRequest.buildCustomAnalyzer(tokenizer).build(text);
        AnalyzeResponse response = restHighLevelClient.indices().analyze(request, RequestOptions.DEFAULT);
        return response.getTokens();
    }

    @Override
    public <T> List<T> termQuery(String key, Class<T> classType, String... values) {
        //查询条件(词条查询：对应ES query里的term)
        TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(key, values);
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(termsQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
//        //获取总记录数
//        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> matchQuery(Operator operator, String analyzer, String key, Class<T> classType, String text) {
        //查询条件(词条查询：对应ES query里的match)
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(key, text).analyzer(analyzer).operator(operator);
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(matchQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());

    }

    @Override
    public <T> List<T> matchAllQuery(Class<T> classType) {
        //查询条件(词条查询：对应ES query里的match)
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(matchAllQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
//        //获取总记录数
//        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> wildcardQuery(String key, String value, Class<T> classType) {
        //查询条件(词条查询：对应ES query里的wildcard)
        WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery(key, value);
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(wildcardQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> prefixQuery(String key, String value, Class<T> classType) {
        //查询条件(词条查询：对应ES query里的prefixQuery)
        PrefixQueryBuilder prefixQueryBuilder = QueryBuilders.prefixQuery(key, value);
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(prefixQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> regexpQuery(String key, String value, Class<T> classType) {
        //查询条件(词条查询：对应ES query里的regexpQuery)
        RegexpQueryBuilder regexpQueryBuilder = QueryBuilders.regexpQuery(key, value);
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(regexpQueryBuilder);

        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> rangeQuery(String name, Integer from, Integer to, Class<T> classType) {
        //查询条件(词条查询：对应ES query里的rangeQuery)
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(name).from(from).to(to);
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(rangeQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> sort(Sort.Direction direction, Class<T> classType, String... properties) {
        //查询条件(词条查询：对应ES query里的sort)
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(matchAllQueryBuilder);
        nativeSearchQuery.addSort(Sort.by(direction, properties));
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> queryStringQuery(Map<String, Float> fields, String queryString, String analyzer, Operator operator, Class<T> classType) {
        //查询条件(词条查询：对应ES query里的queryStringQuery)
        QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(queryString).fields(fields).analyzer(analyzer).defaultOperator(operator);
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryStringQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> boolQueryBuilderByMust(Map<String, String[]> fields, Class<T> classType) {
        //构建boolQuery(词条查询：对应ES query里的bool)对多个查询条件连接
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        fields.forEach((key, value1) -> {
            //查询条件(词条查询：对应ES query里的termQuery)
            TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(key, value1);
//            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(key, value1);
            boolQueryBuilder.must(termsQueryBuilder);

        });

        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(boolQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> boolQueryBuilderByFilter(Map<String, String[]> fields, Class<T> classType) {
        //构建boolQuery(词条查询：对应ES query里的bool)对多个查询条件连接
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        fields.forEach((key, value1) -> {
            //查询条件(词条查询：对应ES query里的termQuery)
            TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(key, value1);
            //must（and）：条件必须成立
            boolQueryBuilder.filter(termsQueryBuilder);
        });

        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(boolQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> boolQueryBuilderByMustNot(Map<String, String[]> fields, Class<T> classType) {
        //构建boolQuery(词条查询：对应ES query里的bool)对多个查询条件连接
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        fields.forEach((key, value1) -> {
            //查询条件(词条查询：对应ES query里的termQuery)
            TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(key, value1);
            //must（and）：条件必须成立
            boolQueryBuilder.mustNot(termsQueryBuilder);
        });

        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(boolQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> List<T> boolQueryBuilderByShould(Map<String, String[]> fields, Integer minimumShouldMatch, Class<T> classType) {
        //构建boolQuery(词条查询：对应ES query里的bool)对多个查询条件连接
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        fields.forEach((key, value1) -> {
            //查询条件(词条查询：对应ES query里的termQuery)
            TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(key, value1);
            //must（and）：条件必须成立
            boolQueryBuilder.should(termsQueryBuilder);
        });
        //参数定义了至少满足几个子句
        boolQueryBuilder.minimumShouldMatch(minimumShouldMatch);
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(boolQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public <T> PageResult<T> highlightBuilder(Integer pageNum, Integer pageSize, String field, String preTags, String postTags, String text, Class<T> classType) {
        //查询条件(词条查询：对应ES query里的match)
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(field, text);
        //
        //设置高亮三要素                                    field: 你的高亮字段    // preTags ：前缀    // postTags：后缀
        HighlightBuilder highlightBuilder = new HighlightBuilder().field(field).preTags(preTags).postTags(postTags);
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(matchQueryBuilder)
                .withPageable(PageRequest.of(pageNum == null || pageNum == 0 ? 0 : pageNum - 1, pageSize))
                .withHighlightBuilder(highlightBuilder).build();
        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        //获取值返回
        List<T> list = search.getSearchHits().stream().map(searchHit -> {
            //获得结果实体
            T content = searchHit.getContent();
            //所有高亮结果
            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
            //遍历高亮结果
            for (Map.Entry<String, List<String>> stringListEntry : highlightFields.entrySet()) {
                String key = stringListEntry.getKey();
                //获取实体反射类
                Class<?> aClass = content.getClass();
                try {
                    //获取该实体属性
                    Field declaredField = aClass.getDeclaredField(key);
                    //权限为私的 解除！
                    declaredField.setAccessible(true);
                    //替换，把高亮字段替换到这个实体对应的属性值上
                    declaredField.set(content, stringListEntry.getValue().get(0));
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            return content;
        }).collect(Collectors.toList());

        return new PageResult<T>(totalHits, list);
    }

    @Override
    public <T> List<T> aggregationBuilder(String name, Class<T> classType, String... values) {
        //构建termsQueryBuilder(词条查询：对应ES query里的terms)不分词查询
        TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(name, values);

        //最大值(max)
        MaxAggregationBuilder maxAggregationBuilder = AggregationBuilders.max("maxAge").field("tAge");
        //最小值(min)
        MinAggregationBuilder minAggregationBuilder = AggregationBuilders.min("minAge").field("tAge");
        //平均值(avg)
        AvgAggregationBuilder avgAggregationBuilder = AggregationBuilders.avg("avgAge").field("tAge");
        //分组(group by)
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("termClassName").field("tClassName");
        //总数(sum)
        SumAggregationBuilder sumAggregationBuilder = AggregationBuilders.sum("sumAge").field("tAge");
        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(termsQueryBuilder).
                //聚合最大值
                        addAggregation(maxAggregationBuilder).
                //聚合最小直
                        addAggregation(minAggregationBuilder).
                //聚合平均值
                        addAggregation(avgAggregationBuilder).
                //聚合总值
                        addAggregation(sumAggregationBuilder).
                //分组后聚合  各组的最大值和各组的总和
                        addAggregation(termsAggregationBuilder.subAggregation(maxAggregationBuilder).subAggregation(sumAggregationBuilder)).
                        build();

        //查询,获取查询结果
        SearchHits<T> search = elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //获取总记录数
        long totalHits = search.getTotalHits();
        for (Aggregation aggregation : Objects.requireNonNull(search.getAggregations())) {
            //查询结果中的总和
            Sum sum = aggregation instanceof Sum ? ((Sum) aggregation) : null;
            Optional.ofNullable(sum).ifPresent(s -> System.err.println(aggregation.getName() + ":" + s.getValue()));
            //查询结果中的最大值
            Max max = aggregation instanceof Max ? ((Max) aggregation) : null;
            Optional.ofNullable(max).ifPresent(s -> System.err.println(aggregation.getName() + ":" + s.getValue()));
            //查询结果中的最小值
            Min min = aggregation instanceof Min ? ((Min) aggregation) : null;
            Optional.ofNullable(min).ifPresent(s -> System.err.println(aggregation.getName() + ":" + s.getValue()));
            //查询结果中的平均值
            Avg avg = aggregation instanceof Avg ? ((Avg) aggregation) : null;
            Optional.ofNullable(avg).ifPresent(s -> System.err.println(aggregation.getName() + ":" + s.getValue()));
            //分组后查询结果
            Terms terms = aggregation instanceof Terms ? (Terms) aggregation : null;
            Optional.ofNullable(terms).ifPresent(s -> System.err.println(aggregation.getName() + ":" + s.getBuckets()));
        }
        //获取值返回
        return search.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public List<String> completionSuggestion(String fieldName, String text, Class<?> classType) {
        //定义反参容器
        List<String> stringList = new ArrayList<>();
        //构建搜索建议补全对象
        CompletionSuggestionBuilder completionSuggestionBuilder = SuggestBuilders.
                completionSuggestion(fieldName). // 使用fieldName入参进行标题联想(这里就是索引被@CompletionField注解标注的字段)
                prefix(text).       // 关键字（参数传此）
                skipDuplicates(true)// 重复过滤
                //.size(100)       // 匹配数量
                ;
        //创建搜索提示对象 进行封装搜索补全
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        //  completionSuggestionBuilder:随便起的搜索补全的名字
        suggestBuilder.addSuggestion("completionSuggestionBuilder", completionSuggestionBuilder);
        //查询es并反参
        SearchResponse searchResponse = elasticsearchRestTemplate.suggest(suggestBuilder, elasticsearchRestTemplate.getIndexCoordinatesFor(classType));
        //获取反参中的搜索补全结果
        Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> suggestionBuilder = searchResponse.getSuggest().getSuggestion("completionSuggestionBuilder");

        // 处理返回
        List<String> suggests = suggestionBuilder.getEntries().stream().map(x -> x.getOptions().stream().map(y -> y.getText().toString()).collect(Collectors.toList())).findFirst().get();
        // 将搜索补全内容保存到容器返回
        for (String suggest : suggests) {
            stringList.add(suggest);
            System.err.println("suggest = " + suggest);
        }
        return stringList;
    }

    @Override
    public List<String> termSuggestion(String fieldName, String text, Class<?> classType) {
        //定义反参容器
        List<String> stringList = new ArrayList<>();
//        构建纠正词条对象  词条建议器(只要是词,短的 比如姓名)
        TermSuggestionBuilder termSuggestionBuilder = SuggestBuilders.termSuggestion(fieldName).text(text);
/*        termSuggestionBuilder.suggestMode(TermSuggestionBuilder.SuggestMode.ALWAYS);/*建议模式（控制提供建议词的方式）：
                                                                                           1. missing：默认方式，仅在‘要搜索词项’不在索引中存在时，才提供建议词；
                                                                                           2. popular：仅提供频率比‘要搜索词项’高的建议词；
                                                                                           3. always：总是提供建议词；*/

        termSuggestionBuilder.sort(SortBy.SCORE);   /*建议词的排序方式：
                                                        1. score：先按评分排序，再按文档频率、term顺序排；
                                                        2. frequency：先按文档频率排序，再按评分、term顺序排*/

        //创建搜索提示对象 进行封装词条纠正
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        //  termSuggestionBuilder:随便起的搜索补全的名字(后面会用到)
        suggestBuilder.addSuggestion("termSuggestionBuilder", termSuggestionBuilder);
        //查询,获取查询结果
        SearchResponse searchResponse = elasticsearchRestTemplate.suggest(suggestBuilder, IndexCoordinates.of(classType.getAnnotation(Document.class).indexName()));
        //获取反参中的词条纠正结果
        Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> suggestionBuilder = searchResponse.getSuggest().getSuggestion("termSuggestionBuilder");

        // 处理返回
        List<String> suggests = suggestionBuilder.getEntries().stream().map(x -> x.getOptions().stream().map(y -> y.getText().toString()).collect(Collectors.toList())).findFirst().get();

        // 将词条纠正内容保存到容器返回
        for (String suggest : suggests) {
            stringList.add(suggest);
            System.err.println("suggest = " + suggest);
        }
        return stringList;
    }

    @Override
    public long queryCount(NativeSearchQuery query, Class<?> classType) {
        //查询总数
        return elasticsearchRestTemplate.count(query, classType);
    }


    public <T> PageResult<T> querylistPage(Integer pageNum, Integer pageSize, JSONObject jsonObject, Class<?> classType,List<String> noLikeParams) {
        //高亮显示
//        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(t));
        //多查询条件  must 可不断添加条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        for (String key : jsonObject.keySet()) {
            if (jsonObject.get(key) != null && StringUtils.isNotBlank(jsonObject.get(key).toString())) {
                if (key.lastIndexOf("TimeStart") > -1) {
                    //时间戳转换
                    RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(key.substring(0,key.lastIndexOf("Start")));
                    //<= 大于等于
                    rangeQueryBuilder.from(jsonObject.get(key));
                    //must（and）：条件必须成立
                    boolQueryBuilder.must(rangeQueryBuilder);
                }else if (key.lastIndexOf("TimeEnd") > -1) {
                    //时间戳转换
                    RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(key.substring(0,key.lastIndexOf("End")));
                    //>= 小于等于
                    rangeQueryBuilder.to(jsonObject.get(key));

                    //must（and）：条件必须成立
                    boolQueryBuilder.must(rangeQueryBuilder);
                }else if (noLikeParams.contains(key)) {
                    boolQueryBuilder.must(QueryBuilders.wildcardQuery( key, "*"+jsonObject.get(key).toString()+"*"));
                } else {
                    int num = jsonObject.get(key).toString().length();
                    String str = jsonObject.get(key).toString();
                    for (int i = 0; i < num; i++) {
                        boolQueryBuilder.must(QueryBuilders.wildcardQuery(key, "*" + str.substring(i, Math.min(num, i + 1)) + "*"));
                    }
//                //精确查询
//                queryBuilder.must(QueryBuilders.termQuery("name.keyword", vo.getName()));
                    //模糊查询
//                queryBuilder.must(QueryBuilders.matchQuery(key, jsonObject.get(key)));
//                boolQueryBuilder.must( QueryBuilders.wildcardQuery( key, "*"+jsonObject.get(key).toString()+"*"));
                }

//                boolQueryBuilder.withPageable(PageRequest.of(pageNum == null || pageNum == 0 ? 0 : pageNum - 1, pageSize));
            }
        }

        //创建查询条件构建器SearchSourceBuilder(对应ES外面的大括号)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(boolQueryBuilder);
        //查询,获取查询结果
        SearchHits<T> search = (SearchHits<T>) elasticsearchRestTemplate.search(nativeSearchQuery, classType);
        //查询总数
        long count = elasticsearchRestTemplate.count(nativeSearchQuery, classType);
        //最终结果集
        List<T> tList = new ArrayList<>();
        //添加高亮查询
        for (SearchHit<T> searchHit : search) {
            //获取普通结果
            tList.add(searchHit.getContent());
        }

        return new PageResult<T>(count, tList);


    }



//    <T> Iterable<T> save(Iterable<T>
    @Override
    public void batchSave(List<Object> list) {
        Assert.notNull(list, "新增的商品规格集合不能为空！");
        Object object = list.get(0);
        // 获取索引文档对象
        Document document = object.getClass().getAnnotation(Document.class);
        List<IndexQuery> queries = new ArrayList<>();
        list.forEach(obj -> {
            IndexQuery indexQuery = new IndexQuery();
            try {
                indexQuery.setObject(obj);
                queries.add(indexQuery);
            } catch (Exception e) {
                log.error("批量新增索引异常:{}", e);
            }
        });
        elasticsearchRestTemplate.bulkIndex(queries,IndexCoordinates.of(document.indexName()));
    }

}
